import { LoggerUtility } from '../logger/logger.utility';
import { DateUtils } from './date.utility';
import { NumberUtils } from './number.utility';
import { StringUtils } from './string.utility';

/**
 * Common utility class
 *
 * @export
 * @class Utility
 */
export class Utility {
    /**
     * The public function is used to return blank list if input is null or undefined.
     *
     * @static
     * @param {any[]} input
     * @returns {Boolean}
     *
     * @memberOf Utility
     */
    public static isBlankList(input: any[]): boolean {
        // tslint:disable-next-line:triple-equals
        return (input == null) || (Array.isArray(input) && input.length === 0);
    }

    /**
     *  The public function is used to return blank list if input is not null or undefined.
     *
     * @static
     * @param {any[]} input
     * @returns {Boolean}
     *
     * @memberOf Utility
     */
    public static isNotBlankList(input: any[]): boolean {
        return !Utility.isBlankList(input);
    }

    // /**
    //  * deep clone method.
    //  *
    //  * @static
    //  * @param {*} fromObj
    //  *
    //  * @memberOf Utility
    //  */
    public static deepCloneObj(fromObj) {
        return JSON.parse(JSON.stringify(fromObj));
    }

    public static deepCloneObjWithFun(fromObj) {
        const stringObj = JSON.stringify(fromObj, (key, val) => {
            if (typeof val === 'function') {
                return val + '';
            }
            return val;
        });

        return JSON.parse(stringObj, (k, v) => {
            if (v.indexOf && v.indexOf('function') > -1) {
                // tslint:disable-next-line:no-eval
                return eval('(function(){return ' + v + ' })()');
            }
            return v;
        });
    }

    /**
     * 拷贝对象  将fromObj的属性值copy到toObj中（toObj中没有对应的值才拷贝，有的话就不拷贝）
     * 用于修改和添加对象时候的对象赋值
     *
     * @static
     * @param {any} toObj
     * @param {any} fromObj
     * @returns
     *
     * @memberOf Utility
     */
    public static copyObj(toObj, fromObj) {
        if (fromObj) {
            for (const key of Object.keys(fromObj)) {
                if (fromObj.hasOwnProperty(key) && fromObj[key]) {
                    toObj[key] = fromObj[key];
                }
            }
        }
        return toObj;
    }

    /**
     * 拷贝对象  将fromObj的所有属性值copy到toObj中
     *
     * @static
     * @param {any} toObj
     * @param {any} fromObj
     * @returns
     *
     * @memberOf Utility
     */
    public static copyObjAll(toObj, fromObj) {
        if (toObj !== null && fromObj !== null) {
            for (const key of Object.keys(fromObj)) {
                toObj[key] = fromObj[key];
            }
        }
        return toObj;
    }

    /**
     * convert from json to string safely
     *
     * @static
     * @param {*} source
     * @returns {string}
     *
     * @memberOf Utility
     */
    public static objToJson(source: any): string {
        // tslint:disable-next-line:triple-equals
        if (source == null) {
            return '';
        } else {
            return JSON.stringify(source);
        }
    }

    /**
     * convert from string to json safely
     *
     * @static
     * @param {string} source
     * @returns {*}
     *
     * @memberOf Utility
     */
    public static jsonToObj(source: string): any {
        // tslint:disable-next-line:triple-equals
        if (source == null) {
            return undefined;
        } else {
            let result = '';
            try {
                result = JSON.parse(source);
            } catch (ex) {
                LoggerUtility.error('Utility.jsonToObj error', ex);
                result = source;
            }
            return result;
        }
    }

    /**
     * get value from object safety
     *
     * @static
     * @template T
     * @template K
     * @param {T} obj
     * @param {K} key
     * @returns
     *
     * @memberOf Utility
     */
    public static getProperty<T, K extends keyof T>(obj: T, key: K) {
        return obj[key];  // 推断类型是T[K]
    }

    /**
     * set value from object safety
     *
     * @static
     * @template T
     * @template K
     * @param {T} obj
     * @param {K} key
     * @param {T[K]} value
     *
     * @memberOf Utility
     */
    public static setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
        obj[key] = value;
    }

    static get Date() {
        return DateUtils;
    }

    static get String() {
        return StringUtils;
    }

    static get Number() {
        return NumberUtils;
    }

    static get UUID() {
        return UUID;
    }
}

/**
 * UUID class
 *
 * @export
 * @class UUID
 */
// tslint:disable-next-line:max-classes-per-file
export class UUID {
    public static next(): string {
        return this.random4() + this.random4() + '-' + this.random4() + '-' + this.random4() + '-' +
            this.random4() + '-' + this.random4() + this.random4() + this.random4();
    }

    private static random4(): string {
        return Math.floor((1 + Math.random()) * 0x10000)
            .toString(16)
            .substring(1);
    }

}
